package cn.iocoder.yudao.module.wms.service.inventoryclassify;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.wms.controller.admin.inventoryclassify.vo.InventoryClassifyPageReqVO;
import cn.iocoder.yudao.module.wms.controller.admin.inventoryclassify.vo.InventoryClassifySaveReqVO;
import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.InventoryDO;
import cn.iocoder.yudao.module.wms.dal.dataobject.inventoryclassify.InventoryClassifyDO;
import cn.iocoder.yudao.module.wms.dal.mysql.inventory.InventoryMapper;
import cn.iocoder.yudao.module.wms.dal.mysql.inventoryclassify.InventoryClassifyMapper;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.*;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.*;

/**
 * 存货分类 Service 实现类
 *
 * @author 曾劲松
 */
@Service
@Validated
public class InventoryClassifyServiceImpl implements InventoryClassifyService {

    @Resource
    private InventoryClassifyMapper inventoryClassifyMapper;

    @Resource
    private InventoryMapper inventoryMapper;

    @Override
    public Long createInventoryClassify(InventoryClassifySaveReqVO createReqVO) {
        validateCodeOrNameExists(createReqVO);
        // 插入
        InventoryClassifyDO inventoryClassify = BeanUtils.toBean(createReqVO, InventoryClassifyDO.class);
        inventoryClassifyMapper.insert(inventoryClassify);
        // 返回
        return inventoryClassify.getId();
    }

    @Override
    public void updateInventoryClassify(InventoryClassifySaveReqVO updateReqVO) {
        // 校验存在
        validateInventoryClassifyExists(updateReqVO.getId());
        validateCodeOrNameExists(updateReqVO);
        // 更新
        InventoryClassifyDO updateObj = BeanUtils.toBean(updateReqVO, InventoryClassifyDO.class);
        inventoryClassifyMapper.updateById(updateObj);
    }

    @Override
    public void deleteInventoryClassify(Long id) {
        // 校验存在
        validateInventoryClassifyExists(id);
        // 校验是否有子分类
        if (inventoryClassifyMapper.selectCount(InventoryClassifyDO::getParentId, id) > 0) {
            throw exception(INVENTORY_CLASSIFY_EXITS_CHILDREN);
        }
        // 校验分类下是否有存货
        if (inventoryMapper.selectCount(InventoryDO::getClassifyId, id) > 0) {
            throw exception(INVENTORY_CLASSIFY_EXITS_INVENTORY);
        }
        // 删除
        inventoryClassifyMapper.deleteById(id);
    }

    /**
     * 校验存货分类是否存在
     * @param id 存货分类id
     */
    private void validateInventoryClassifyExists(Long id) {
        if (inventoryClassifyMapper.selectById(id) == null) {
            throw exception(INVENTORY_CLASSIFY_NOT_EXISTS);
        }
    }

    /**
     * 校验编码或名称是否存在
     * @param reqVO 存货分类Request VO
     */
    private void validateCodeOrNameExists(InventoryClassifySaveReqVO reqVO) {
        if (inventoryClassifyMapper.selectCount(InventoryClassifyDO::getCode, reqVO.getCode()) > 0) {
            throw exception(INVENTORY_CLASSIFY_CODE_EXISTS);
        }
        if (inventoryClassifyMapper.selectCount(InventoryClassifyDO::getName, reqVO.getName()) > 0) {
            throw exception(INVENTORY_CLASSIFY_NAME_EXISTS);
        }
    }

    @Override
    public InventoryClassifyDO getInventoryClassify(Long id) {
        return inventoryClassifyMapper.selectById(id);
    }

    @Override
    public PageResult<InventoryClassifyDO> getInventoryClassifyPage(InventoryClassifyPageReqVO pageReqVO) {
        return inventoryClassifyMapper.selectPage(pageReqVO, getClassifyCondition(pageReqVO.getParentId()));
    }

    @Override
    public List<InventoryClassifyDO> getInventoryClassifyList() {
        return inventoryClassifyMapper.selectList();
    }

    @Override
    public List<InventoryClassifyDO> getChildInventoryClassifyList(Collection<Long> ids) {
        List<InventoryClassifyDO> children = new LinkedList<>();
        // 遍历每一层
        Collection<Long> parentIds = ids;
        for (int i = 0; i < Short.MAX_VALUE; i++) {
            List<InventoryClassifyDO> classifys = inventoryClassifyMapper.selectList(InventoryClassifyDO::getParentId, parentIds);
            if (CollUtil.isEmpty(classifys)) {
                break;
            }
            children.addAll(classifys);
            parentIds = convertSet(classifys, InventoryClassifyDO::getId);
        }
        return children;
    }

    /**
     * 获得存货分类条件：查询指定存货分类的子分类编号们，包括自身
     *
     * @param classifyId 存货分类编号
     * @return 存货分类编号集合
     */
    private Set<Long> getClassifyCondition(Long classifyId) {
        if (classifyId == null) {
            return Collections.emptySet();
        }
        Set<Long> classifyIds = convertSet(getChildInventoryClassifyList(Collections.singleton(classifyId)), InventoryClassifyDO::getId);
        classifyIds.add(classifyId); // 包括自身
        return classifyIds;
    }

}